﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using AFT.Parking.Entity.ArgumentEntity;
using AFT.Parking.Foundation;
using AFT.Parking.Foundation.Data;
using NHibernate;
using NHibernate.Linq;

namespace AFT.Parking.Data
{
    public class NHibernateRepository : IRepository
    {
        #region GetSession

        /// <summary>
        /// 获取Session对象
        /// </summary>
        private ISession iSession
        {
            get
            {
                string dataBaseName = "ParkingDB";
                //if (IsWrite)
                //{
                //    dataBaseName = "WriteDB";
                //}
                //else
                //{
                //    dataBaseName = "ReadDB";
                //}
                return NHibernateHelper.GetSession(dataBaseName);
            }
        }

        private bool _IsWrite = true;
        /// <summary>
        /// 标识当前操作为读抑或是写（用于数据库读写分离）
        /// </summary>
        private bool IsWrite
        {
            get { return _IsWrite; }
            set { _IsWrite = value; }
        }

        #endregion

        /// <summary>
        /// 提供LINQ使用的可查询对象
        /// </summary>
        public virtual IQueryable<T> AsQueryable<T>() where T : class, IEntity
        {
            IsWrite = false;
            IQueryable<T> result = iSession.Query<T>();
            return result;
        }

        /// <summary>
        /// 根据条件表达式获取满足条件的所有类型为T的数据
        /// </summary>
        /// <param name="expression">条件表达式</param>
        /// <returns>返回满足条件的所有类型为T的数据</returns>
        public virtual IQueryable<T> Find<T>(Expression<Func<T, bool>> expression) where T : class, IEntity
        {
            IsWrite = false;
            IQueryable<T> result = iSession.Query<T>().Where<T>(expression);
            return result;
        }

        /// <summary>
        /// 根据条件表达式获取满足条件的所有类型为T的数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">条件表达式</param>
        /// <param name="orderByExpression">排序表达式</param>
        /// <param name="OrderBy">true=降序 false=升序</param>
        /// <returns></returns>
        public virtual IQueryable<T> Find<T>(Expression<Func<T, bool>> expression, List<OrderBy<T>> SortList) where T : class, IEntity
        {
            IsWrite = false;
            IQueryable<T> result = iSession.Query<T>().Where<T>(expression);
            foreach (var obj in SortList)
            {
                if (!obj.Sort)
                    result = result.OrderByDescending(obj.exp);
                else
                    result = result.OrderBy(obj.exp);
            }
            return result;
        }

        /// <summary>
        /// 根据条件表达式统计满足条件的数据条数
        /// </summary>
        /// <param name="expression">条件表达式</param>
        /// <returns>满足条件的记录数量</returns>
        public virtual long Count<T>(Expression<Func<T, bool>> expression) where T : class, IEntity
        {
            IsWrite = false;
            long lCount = iSession.Query<T>().Count(expression);
            return lCount;
        }

        /// <summary>
        /// 根据条件表达式判断是否存在符合条件的数据
        /// </summary>
        /// <param name="expression">条件表达式</param>
        /// <returns>如果存在满足条件的数据 返回True 否则 False</returns>
        public virtual bool Exists<T>(Expression<Func<T, bool>> expression) where T : class, IEntity
        {
            IsWrite = false;
            return iSession.Query<T>().Any(expression);
        }

        /// <summary>
        /// 根据主键获取类型为T的数据 如果不存在则返回null
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>返回类型为T的数据</returns>
        public virtual T Get<T>(object id) where T : class, IEntity
        {
            IsWrite = false;
            T model = iSession.Get<T>(id);
            return model;
        }

        /// <summary>
        /// 根据主键加载类型为T的数据 如果不存在则返回默认实体
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>返回类型为T的数据</returns>
        public virtual T Load<T>(object id) where T : class, IEntity
        {
            IsWrite = false;
            T model = iSession.Load<T>(id);
            return model;
        }

        /// <summary>
        /// 根据条件表达式获取满足条件的首个类型为T的数据,如果不存在则返回NULL
        /// </summary>
        /// <param name="expression">条件表达式</param>
        /// <returns>返回满足条件的首个类型为T的数据</returns>
        public virtual T First<T>(Expression<Func<T, bool>> expression) where T : class, IEntity
        {
            IsWrite = false;
            T model = iSession.Query<T>().FirstOrDefault<T>(expression);
            return model;
        }

        /// <summary>
        /// 获取指定分页类型为T的数据
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页数据量</param>
        /// <returns>返回满足条件的所有类型为T的数据和分页信息</returns>
        public virtual IPagedList<T> FindPagedList<T>(int pageIndex, int pageSize) where T : class, IEntity
        {
            IsWrite = false;
            IPagedList<T> result = new PagedList<T>(AsQueryable<T>(), pageIndex, pageSize);
            return result;
        }

        /// <summary>
        /// 根据条件表达式获取满足条件的所有类型为T的数据
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页数据量</param>
        /// <param name="expression">条件表达式</param>
        /// <returns>返回满足条件的所有类型为T的数据和分页信息</returns>
        public virtual IPagedList<T> FindPagedList<T>(int pageIndex, int pageSize, Expression<Func<T, bool>> expression) where T : class, IEntity
        {
            IsWrite = false;
            IPagedList<T> result = new PagedList<T>(Find<T>(expression), pageIndex, pageSize);
            return result;
        }

        /// <summary>
        /// 根据条件表达式获取满足条件的所有类型为T的数据
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页数据量</param>
        /// <param name="expression">条件表达式</param>
        /// <param name="orderBy">排序表达式 如: Column1 ASC,Column2 DESC</param>
        /// <returns>返回满足条件的所有类型为T的数据和分页信息</returns>
        public virtual IPagedList<T> FindPagedList<T>(int pageIndex, int pageSize, Expression<Func<T, bool>> expression, List<OrderBy<T>> SortList) where T : class, IEntity
        {
            IsWrite = false;
            IPagedList<T> result = new PagedList<T>(Find<T>(expression, SortList), pageIndex, pageSize);
            return result;
        }

        /// <summary>
        /// 删除某个类型为T的数据
        /// </summary>
        /// <param name="item">待删除数据</param>
        public virtual void Delete<T>(T item) where T : class, IEntity
        {
            IsWrite = true;
            var session = this.iSession;
            session.Delete(item);
            session.Flush();
        }

        /// <summary>
        /// 根据条件表达式获取满足条件的所有类型为T的数据
        /// </summary>
        /// <param name="expression">条件表达式</param>
        /// <returns>返回受影响的行数</returns>
        public virtual int Delete<T>(Expression<Func<T, bool>> expression) where T : class, IEntity
        {
            IsWrite = true;
            List<T> list = (from p in Find<T>(expression)
                            select p).ToList<T>();
            int i = DeleteList<T>(list);
            return i;
        }

        /// <summary>
        /// 删除所有类型为T的数据 警告:危险!!!该操作为不可逆操作,使用前请仔细确认!
        /// </summary>
        /// <returns>返回受影响的行数</returns>
        public virtual int DeleteAll<T>() where T : class,IEntity
        {
            IsWrite = true;
            List<T> list = (from p in AsQueryable<T>()
                            select p).ToList<T>();
            int i = DeleteList<T>(list);
            return i;
        }

        /// <summary>
        /// 批量删除数据公用方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        private int DeleteList<T>(List<T> list) where T : class,IEntity
        {
            IsWrite = true;
            ISession session = this.iSession;
            int i = 0;
            using (ITransaction tx = session.BeginTransaction())
            {
                try
                {
                    foreach (var obj in list)
                    {
                        session.Delete(obj);
                        i++;
                    }
                    tx.Commit();
                }
                catch
                {
                    tx.Rollback();
                    i = 0;
                }
            }
            return i;
        }

        /// <summary>
        /// 保存新的类型为T的数据对象(主键ID会根据配置产生)
        /// </summary>
        /// <param name="item">待保存的对象</param>
        /// <returns>返回新对象的主键ID</returns>
        public virtual object Save<T>(T item) where T : class, IEntity
        {
            IsWrite = true;
            ISession session = this.iSession;
            object obj = session.Save(item);
            session.Flush();
            return obj;
        }

        /// <summary>
        /// 保存或更新一个已存在的数据对象 注：web开发中请单独使用Save或者Update方法
        /// </summary>
        /// <param name="item">待保存/更新的对象</param>
        /// <returns>返回已保存的对象</returns>
        public virtual T SaveOrUpdate<T>(T item) where T : class, IEntity
        {
            IsWrite = true;
            var session = this.iSession;
            session.SaveOrUpdate(item);
            session.Flush();
            return item;
        }

        /// <summary>
        /// 保存或更新一个已存在的数据对象 注：web开发中请单独使用Save或者Update方法
        /// </summary>
        /// <param name="item">待保存/更新的对象</param>
        /// <returns>返回已保存的对象</returns>
        public virtual T SaveOrUpdateCopy<T>(T item) where T : class, IEntity
        {
            IsWrite = true;
            var session = this.iSession;
            session.SaveOrUpdateCopy(item);
            session.Flush();
            return item;
        }

        /// <summary>
        /// 更新指定的类型为T的对象
        /// </summary>
        /// <param name="item">待更新的对象</param>
        public virtual void Update<T>(T item) where T : class, IEntity
        {
            IsWrite = true;
            var session = this.iSession;
            session.Update(item);
            session.Flush();
        }
    }
}
